package org.example.designPattern;


/*
    单例模式
    只有一个对象实例  对单例类实例化 只会得到一个实例
 */
public class Singleton {
    /*
       开放封闭原则    对扩展开放 修改关闭
       里氏代换原则    子类可以完美替换基类
       依赖倒转原则    依赖于抽象不依赖于具体
       接口隔离原则    接口之间相互隔离
       迪米特法则      一个对象应该尽可能的减少对其它对象的依赖
       单一职责原则    一个方法负责一件事情
     */
    private static boolean flag = false;

    private Singleton() {
        if (flag == false) {
            flag = !flag;
        } else {
            throw new RuntimeException("单例模式被侵犯！");
        }
    }
}

//饿汉式
class Demo1 {
    //1. 饿汉式:类初始化时,会立即加载该对象，线程天生安全,调用效率高。
    // 类初始化时,会立即加载该对象，线程安全,调用效率高
    private static Demo1 demo1 = new Demo1();

    private Demo1() {
        System.out.println("私有Demo1构造参数初始化");
    }

    public static Demo1 getInstance() {
        return demo1;
    }

    public static void main(String[] args) {
        Demo1 s1 = Demo1.getInstance();
        Demo1 s2 = Demo1.getInstance();
        System.out.println(s1 == s2);
    }
}

//懒汉式
class Demo2 {
    //懒汉式: 类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
    //类初始化时，不会初始化该对象，真正需要使用的时候才会创建该对象。
    private static Demo2 demo2;

    private Demo2() {
        System.out.println("私有Demo2构造参数初始化");
    }

    public synchronized static Demo2 getInstance() {
        if (demo2 == null) {
            demo2 = new Demo2();
        }
        return demo2;
    }

    public static void main(String[] args) {
        Demo2 s1 = Demo2.getInstance();
        Demo2 s2 = Demo2.getInstance();
        System.out.println(s1 == s2);
    }
}

// 静态内部类方式
class Demo3 {
    // 静态内部方式:结合了懒汉式和饿汉式各自的优点，真正需要对象的时候才会加载，加载类是线程
    //安全的。
    private Demo3() {
        System.out.println("私有Demo3构造参数初始化");
    }

    public static class SingletonClassInstance {
        private static final Demo3 DEMO_3 = new Demo3();
    }

    // 方法没有同步
    public static Demo3 getInstance() {
        return SingletonClassInstance.DEMO_3;
    }

    public static void main(String[] args) {
        Demo3 s1 = Demo3.getInstance();
        Demo3 s2 = Demo3.getInstance();
        System.out.println(s1 == s2);
    }
}

class Demo4 {
    //枚举单例: 使用枚举实现单例模式 优点:实现简单、调用效率高，枚举本身就是单例，由jvm从根本
    //上提供保障!避免通过反射和反序列化的漏洞， 缺点没有延迟加载。
    public static Demo4 getInstance() {
        return Demo.INSTANCE.getInstance();
    }

    public static void main(String[] args) {
        Demo4 s1 = Demo4.getInstance();
        Demo4 s2 = Demo4.getInstance();
        System.out.println(s1 == s2);
    }

    //定义枚举
    private static enum Demo {
        INSTANCE;
        // 枚举元素为单例
        private Demo4 demo4;

        Demo() {
            System.out.println("枚举Demo私有构造参数");
            demo4 = new Demo4();
        }

        public Demo4 getInstance() {
            return demo4;
        }
    }
}

class Demo5 {
    //双重检测锁方式 (因为JVM本质重排序的原因，可能会初始化多次，不推荐使用)
    private static Demo5 demo5;
    private Demo5() {
        System.out.println("私有Demo4构造参数初始化");
    }
    public static Demo5 getInstance() {
        if (demo5 == null) {
            synchronized (Demo5.class) {
                if (demo5 == null) {
                    demo5 = new Demo5();
                }
            }
        }
        return demo5;
    }
    public static void main(String[] args) {
        Demo5 s1 = Demo5.getInstance();
        Demo5 s2 = Demo5.getInstance();
        System.out.println(s1 == s2);
    }
}